package com.mspbots.teams.schedule;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mspbots.api.client.CoreClient;
import com.mspbots.teams.config.PropertiesConfiguration;
import com.mspbots.teams.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Jay Yang
 * @date
 */
@Slf4j
@Component
public class NoReceivedUserSchedule {

    private final PropertiesConfiguration.TeamsProperties teamsProperties;
    private final CoreClient coreClient;
    private final RedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    private static final String REDIS_KEY_PREFIX_TENANT = "MSPBOTS:CONFIG:TENANT:";

    public NoReceivedUserSchedule(PropertiesConfiguration.TeamsProperties teamsProperties, CoreClient coreClient, RedisTemplate redisTemplate, ObjectMapper objectMapper) {
        this.teamsProperties = teamsProperties;
        this.coreClient = coreClient;
        this.redisTemplate = redisTemplate;
        this.objectMapper = objectMapper;
    }

//    @Scheduled(cron = "0 0 7 * * ?")
    @Scheduled(cron = "${mspbots.fixedDelay.checkNoReceivedTeamsUser}")
    public void checkNoReceivedTeamsUser(){
        checkNoReceivedTeamsUser(null);
    }

    public void checkNoReceivedTeamsUser(Integer tenantId) {
        System.out.println(teamsProperties.getDay());
        LocalDateTime checkTime = LocalDateTime.now();
        LocalDateTime startTime = checkTime.minusDays(teamsProperties.getDay());
        List<TenantDTO> tenantDTOS = new ArrayList<>();

        if (!ObjectUtils.isEmpty(tenantId)){
            tenantDTOS.add(TenantDTO.builder().id(tenantId).build());
        }else{
            List tenants = redisTemplate.opsForList().range(REDIS_KEY_PREFIX_TENANT + "tenants", 0, -1);
            if (CollectionUtils.isEmpty(tenants)){
                return;
            }
            tenantDTOS = objectMapper.convertValue(tenants, new TypeReference<>() {});
        }
        tenantDTOS.stream().filter(item -> item.getStatusId() == 1).forEach(t -> {
            JsonNode tenantNode = coreClient.get("/teams/user/" + t.getId()).block();
            List<TeamsUser> allUserList = objectMapper.convertValue(tenantNode, new TypeReference<>() {});
            if (!CollectionUtils.isEmpty(allUserList)){
                //get no received teams user
                addNoReceivedTeamsUser(checkTime, startTime, t, allUserList);
                //get no talked teams user
                addNoTalkedTeamsUser(checkTime, startTime, t, allUserList);
            }
        });
        if (!ObjectUtils.isEmpty(tenantId)){
            coreClient.get("/teams/no-message/user/deleteBatch", Map.of("tenantId",tenantId,"checkTime",checkTime)).block();
        }else{
            coreClient.get("/teams/no-message/user/deleteBatch", Map.of("checkTime",checkTime)).block();
        }
    }

    private void addNoReceivedTeamsUser(LocalDateTime checkTime, LocalDateTime startTime, TenantDTO t, List<TeamsUser> allUserList) {
        JsonNode messageNode = coreClient.get("/teams/messages/list/user",
                Map.of("tenantId",t.getId(),"createDate",startTime)).block();
        List<Messages> messageList = objectMapper.convertValue(messageNode, new TypeReference<>() {});

        JsonNode scriptNode = coreClient.get("/script/list",
                Map.of("tenantId",t.getId(),"enable",true)).block();
        List<Messages> scriptList = objectMapper.convertValue(scriptNode, new TypeReference<>() {});
        boolean finalIsBotsUninstalled = CollectionUtils.isEmpty(scriptList) ? true : false;

        Set<String> excludeUserIds = new HashSet<>();
        if (!CollectionUtils.isEmpty(messageList)){
            messageList.stream().forEach(m ->{
                if (m.getStatus().equalsIgnoreCase("received")){
                    excludeUserIds.add(m.getTeamsUserId());
                }else if (m.getStatus().equalsIgnoreCase("ready")
                        && m.getExpireDate().isBefore(checkTime)){
                    excludeUserIds.add(m.getTeamsUserId());
                }
            });
        }
        List<TeamsUserNoMessage> userNoReceivedList = new ArrayList<>();
        allUserList.stream().filter(u-> !excludeUserIds.contains(u.getTeamsUserId())).forEach(u ->{
            TeamsUserNoMessage user = TeamsUserNoMessage.builder()
                    .tenantId(u.getTenantId())
                    .teamsUserId(u.getTeamsUserId())
                    .teamsUserName(u.getTeamsDisplayName())
                    .checkTime(checkTime)
                    .isBotsUninstalled(finalIsBotsUninstalled)
                    .isMessageBlocked(true)
                    .build();
            userNoReceivedList.add(user);
        });
        coreClient.post("/teams/no-message/user/insertBatch/" + t.getId(), userNoReceivedList).block();
    }

    private void addNoTalkedTeamsUser(LocalDateTime checkTime, LocalDateTime startTime, TenantDTO t, List<TeamsUser> allUserList) {
        JsonNode talkNode = coreClient.get("/teams/user-message/list-date",
                Map.of("tenantId",t.getId(),"createDate",startTime)).block();
        List<TeamsUserMessage> talkList = objectMapper.convertValue(talkNode, new TypeReference<>() {});
        List<TeamsUserNoMessage> userNoTalkList = new ArrayList<>();
        Set<String> userIds = CollectionUtils.isEmpty(talkList) ? new HashSet<>()
                : talkList.stream().map(TeamsUserMessage::getTeamsUserId).collect(Collectors.toSet());

        allUserList.stream().filter(u-> !userIds.contains(u.getTeamsUserId())).forEach(u ->{
            TeamsUserNoMessage user = TeamsUserNoMessage.builder()
                    .tenantId(u.getTenantId())
                    .teamsUserId(u.getTeamsUserId())
                    .teamsUserName(u.getTeamsDisplayName())
                    .checkTime(checkTime)
                    .isNeverTalked(true)
                    .build();
            userNoTalkList.add(user);
        });
        coreClient.post("/teams/no-message/user/insertBatch/" + t.getId(), userNoTalkList).block();
    }
}
